package com.huanghuai.retail.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huanghuai.retail.common.CustomException;
import com.huanghuai.retail.common.R;
import com.huanghuai.retail.dto.InformationDto;
import com.huanghuai.retail.dto.SInventoryDto;
import com.huanghuai.retail.entity.PInformation;
import com.huanghuai.retail.entity.SInventory;
import com.huanghuai.retail.entity.Storage;
import com.huanghuai.retail.mapper.SInventoryMapper;
import com.huanghuai.retail.service.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author You do
 * @description 针对表【s_inventory】的数据库操作Service实现
 * @createDate 2023-05-03 21:06:19
 */
@Service
public class SInventoryServiceImpl
        extends ServiceImpl<SInventoryMapper, SInventory>
        implements SInventoryService {

    @Autowired
    private InformationService informationService;

    @Autowired
    private StorageService storageService;

    @Autowired
    private ISWarnInfoService warnInfoService;

    /**
     * 根据库存id或产品id删除，并且库存量为0
     *
     * @param id        id
     * @param productId 产品id
     * @return boolean
     */
    @Override
    public boolean deleteIfNumIsZero(Long id, Long productId, Long storageId) {
        // 条件构造器
        LambdaQueryWrapper<SInventory> sInventoryLambdaQueryWrapper
                = new LambdaQueryWrapper<>();
        sInventoryLambdaQueryWrapper
                .eq(storageId != null,
                        SInventory::getStorageId, storageId)
                .eq(productId != null,
                        SInventory::getProductId, productId)
                .eq(id != null, SInventory::getId, id);
        SInventory inventory = this.getOne(sInventoryLambdaQueryWrapper);
        if (inventory == null) {
            throw new CustomException("删除失败，当前产品不存在");
        } else if (inventory.getNumber() > 0) {
            throw new CustomException("删除失败，当前产品仍有库存");
        }
        return this.removeById(inventory.getId());
    }

    /**
     * 通过产品id查询产品库存量
     *
     * @param productId 产品id
     * @return {@link SInventoryDto}
     */
    @Override
    public List<SInventoryDto> getByIdWithDto(Long productId) {
        // 条件构造器
        LambdaQueryWrapper<SInventory> sInventoryLambdaQueryWrapper =
                new LambdaQueryWrapper<>();
        // 根据产品ID查询到该产品
        sInventoryLambdaQueryWrapper
                .eq(SInventory::getProductId, productId);
        List<SInventory> inventoryList =
                this.list(sInventoryLambdaQueryWrapper);
        // 产品库存DTO集合
        List<SInventoryDto> inventoryDtoList = new ArrayList<>();
        // 根据产品ID获取产品信息
        PInformation information = informationService.getById(productId);
        // 仓库ids
        List<Long> storageIds = new ArrayList<>();
        // 仓库ID和仓库信息一一对应
        Map<Long, Storage> storageInfo = new HashMap<>();
        inventoryList.forEach(item -> {
            SInventoryDto inventoryDto = new SInventoryDto();
            BeanUtils.copyProperties(item, inventoryDto);
            if (information != null) {
                inventoryDto.setPInformation(information);
            }
            inventoryDtoList.add(inventoryDto);
            storageIds.add(item.getStorageId());
        });
        if (storageIds.size() > 0) {
            // 根据仓库ID查询到指定的仓库
            List<Storage> storageList =
                    storageService.listByIds(storageIds);
            // 将仓库信息和仓库ID对应起来
            storageList.forEach(item -> {
                storageInfo.put(item.getId(), item);
            });
            // 将仓库名字封装进库存dto
            inventoryDtoList.forEach(item -> {
                item.setStorage(storageInfo.get(item.getStorageId()));
            });
        }
        return inventoryDtoList;
    }

    /**
     * 分页查询所有库存信息
     *
     * @param page        页面
     * @param pageSize    页面大小
     * @param productName 产品名称
     * @param storagesIds 存储id
     * @param typeIds     类型id
     * @return {@link Page}<{@link SInventoryDto}>
     */
    @Override
    public Page<SInventoryDto> pageDto(Integer page, Integer pageSize,
                                       String productName, Long[] storagesIds,
                                       Long[] typeIds) {
        // 构造库存分页器
        Page<SInventory> sInventoryPage = new Page<>(page, pageSize);
        // 构造库存dto分页器
        Page<SInventoryDto> inventoryDtoPage =
                new Page<>(page, pageSize);
        // 条件构造器
        LambdaQueryWrapper<SInventory> sInventoryLambdaQueryWrapper =
                new LambdaQueryWrapper<>();
        if (storagesIds != null && storagesIds.length > 0) {
            sInventoryLambdaQueryWrapper.in(SInventory::getStorageId,
                    Arrays.asList(storagesIds));
        }
        // 根据产品信息模糊查询
        if (StringUtils.isNotBlank(productName)
                || (typeIds != null && typeIds.length != 0)) {
            // 符合产品信息模糊查询的产品
            List<PInformation> informationList = new ArrayList<>();
            // 产品条件构造器
            LambdaQueryWrapper<PInformation> informationLambdaQueryWrapper =
                    new LambdaQueryWrapper<>();
            // 根据产品名称模糊查询
            informationLambdaQueryWrapper
                    .like(StringUtils.isNotBlank(productName),
                            PInformation::getName, productName);
            // 根据仓库id查询
            if (typeIds != null && typeIds.length != 0) {
                informationLambdaQueryWrapper.in(PInformation::getTypeId,
                        Arrays.asList(typeIds));
            }
            informationList =
                    informationService.list(informationLambdaQueryWrapper);
            // 没有符合要求的产品直接返回空的分页对象
            if (informationList.size() == 0) {
                return inventoryDtoPage;
            }
            // 拿到所有复合要求的产品id
            List<Long> productIdsByName = new ArrayList<>();
            informationList.forEach(item ->
                    productIdsByName.add(item.getId()));
            sInventoryLambdaQueryWrapper
                    .in(SInventory::getProductId, productIdsByName);
        }
        // 进行分页查询
        this.page(sInventoryPage, sInventoryLambdaQueryWrapper);
        // 获取分页查询的记录
        List<SInventory> inventoryList = sInventoryPage.getRecords();
        // 产品id集合
        List<Long> productIds = new ArrayList<>();
        // 产品所在的仓库ID集合
        List<Long> storageIds = new ArrayList<>();
        // 库存dto集合
        List<SInventoryDto> inventoryDtoList = new ArrayList<>();
        // 遍历分页查询到的记录并进行相关操作
        inventoryList.forEach(inventory -> {
            // 获取产品id
            productIds.add(inventory.getProductId());
            // 获取仓库id
            storageIds.add(inventory.getStorageId());
            // 将库存封装为库存dto
            SInventoryDto inventoryDto = new SInventoryDto();
            BeanUtils.copyProperties(inventory, inventoryDto);
            // 添加到库存dto列表中
            inventoryDtoList.add(inventoryDto);
        });
        Map<Long, InformationDto> products = new HashMap<>();
        if (productIds.size() > 0) {
            // 获取到已经查询到的库存对应的产品
            List<InformationDto> informationDtoList =
                    informationService.findInformationDto();
            informationDtoList = informationDtoList
                    .stream().filter(item -> productIds
                            .contains(item.getId()))
                    .collect(Collectors.toList());
            // 将产品id与产品名称对应
            informationDtoList.forEach(item -> {
                products.put(item.getId(), item);
            });
        }
        Map<Long, Storage> storages = new HashMap<>();
        if (storageIds.size() > 0) {
            // 获取到已查询到的库存对应的仓库
            List<Storage> storageList =
                    storageService.listByIds(storageIds);
            // 将仓库名称与id一一对应
            storageList.forEach(item -> {
                storages.put(item.getId(), item);
            });
        }
        // 在库存dto中封装产品名称及仓库名称
        inventoryDtoList.forEach(item -> {
            item.setPInformation(products.get(item.getProductId()));
            item.setStorage(storages.get(item.getStorageId()));
        });
        // 向inventoryDtoPage中写入数据
        BeanUtils.copyProperties(sInventoryPage, inventoryDtoPage);
        inventoryDtoPage.setRecords(inventoryDtoList);
        return inventoryDtoPage;
    }

    @Override
    public boolean updateByProIdWithStorageId(SInventory inventory) {
        // 构造条件构造器，通过产品id查询
        LambdaQueryWrapper<SInventory> sInventoryLambdaQueryWrapper
                = new LambdaQueryWrapper<>();
        sInventoryLambdaQueryWrapper
                .eq(SInventory::getProductId,
                        inventory.getProductId())
                .eq(SInventory::getStorageId,
                        inventory.getStorageId());
        // 更新指定产品的库存
        boolean update = this.update(inventory,
                sInventoryLambdaQueryWrapper);
        // 如果更新成功，触发报警判断
        if (update) {
            SInventory inventoryTmp = this.getOne(sInventoryLambdaQueryWrapper);
            if (inventoryTmp != null) {
                try {
                    warnInfoService.addWhenNeed(inventoryTmp);
                } catch (Exception e) {
                    log.error(e.getMessage());
                }
            }
        }
        return update;
    }

    @Override
    public Map<Long,String> findShopIdByStorageId(Integer storageId) {
        if (storageId !=null) {
            LambdaQueryWrapper<SInventory> queryWrapper = new LambdaQueryWrapper();
            queryWrapper.select(SInventory::getProductId).eq(SInventory::getStorageId, storageId);
            List<SInventory> sInventories = this.list(queryWrapper);
            if(sInventories.size()>0){
                List<Long> shopId = sInventories.stream().map(SInventory::getProductId).collect(Collectors.toList());
                LambdaQueryWrapper<PInformation> informationLambdaQueryWrapper = new LambdaQueryWrapper<>();
                informationLambdaQueryWrapper.select(PInformation::getName,PInformation::getId).in(PInformation::getId, shopId);
                List<PInformation> pInformations = informationService.list(informationLambdaQueryWrapper);
                Map<Long,String> map = new HashMap<>();
                for (PInformation pInformation : pInformations) {
                    map.put(pInformation.getId(),pInformation.getName());
                }
                return map;
            }
            return null;
        }
        return null;

    }

    @Override
    public Integer getNumByProductId(Long productId,Long storageId) {

        if(productId==null && storageId==null)
            return null;

        LambdaQueryWrapper<SInventory> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SInventory::getProductId,productId).eq(SInventory::getStorageId,storageId);
        SInventory one = getOne(queryWrapper);

        return one.getNumber();
    }


    @Override
    public Integer getNumsByStorageId(Long storageId) {
        if (storageId == null){
            return null;
        }
        int numbers = 0;
        LambdaQueryWrapper<SInventory> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.select(SInventory::getNumber).eq(SInventory::getStorageId, storageId);
        List<SInventory> numList = this.list(queryWrapper);
        for (SInventory nums : numList){
            int number = nums.getNumber();
            numbers += number;
        }
        return numbers;
    }

    @Override
    public Long getStorageIdByProductId(Long productId, Long storageId) {
        if (productId == null && storageId == null){
            return null;
        }

        LambdaQueryWrapper<SInventory> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.select(SInventory::getStorageId).eq(SInventory::getProductId, productId);
        List<SInventory> inventoryList = this.list(queryWrapper);
        Long id = null;
        for (SInventory inventory : inventoryList){
            Long stoId = inventory.getStorageId();
            if(stoId != storageId){
                continue;
            }
            id = stoId;
        }
        return id;
    }
}




